package tools

import (
	"bytes"
	"crypto/ecdsa"
	"crypto/md5"
	"crypto/rand"
	"crypto/rsa"
	"crypto/sha256"
	"crypto/x509"
	"encoding/base64"
	"encoding/hex"
	"encoding/json"
	"encoding/pem"
	"fmt"
	"github.com/ethereum/go-ethereum/common/hexutil"
	"github.com/ethereum/go-ethereum/crypto"
	"github.com/mr-tron/base58"
	"io/ioutil"
	"log"
	"math/big"
	"net/http"
	"os"
	"regexp"
	"time"
)

func GenerateAPIKey(userID string, registrationTime time.Time) string {
	// 将用户ID和注册时间转换为字符串
	data := userID + registrationTime.String()

	// 使用SHA256哈希函数生成API密钥
	hash := sha256.Sum256([]byte(data))
	APIKey := fmt.Sprintf("%x", hash)

	return APIKey
}

func EtherStrToWeiBigInt(etherStr string, decimals uint) (*big.Int, bool) {
	etherAmount := new(big.Float)
	_, ok := etherAmount.SetString(etherStr)
	if !ok {
		return nil, false
	}

	// 计算代币单位，即1 Ether等于10的decimals次方Wei
	tokenUnit := new(big.Float).SetInt(new(big.Int).Exp(big.NewInt(10), big.NewInt(int64(decimals)), nil))

	// 将Ether数量乘以单位得到Wei
	wei := new(big.Int)
	etherAmount.Mul(etherAmount, tokenUnit).Int(wei)

	return wei, true
}

// EtherBigIntToWeiStr 将Ether的*big.Float转换为Wei的字符串形式
func EtherBigIntToWeiStr(ether *big.Float, decimals uint) string {
	tokenUnit := new(big.Float).SetInt(new(big.Int).Exp(big.NewInt(10), big.NewInt(int64(decimals)), nil))
	wei := new(big.Int)
	ether.Mul(ether, tokenUnit).Int(wei)
	return wei.String()
}

func WeiStrToEtherBigInt(weiStr string, decimals uint) (*big.Float, bool) {
	wei := new(big.Int)
	_, ok := wei.SetString(weiStr, 10)
	if !ok {
		return nil, false
	}

	ether := new(big.Float).SetInt(wei)
	tokenUnit := new(big.Float).SetInt(new(big.Int).Exp(big.NewInt(10), big.NewInt(int64(decimals)), nil))
	ether.Quo(ether, tokenUnit).SetPrec(4)

	return ether, true
}

func StrEtherBigInt(weiStr string, decimals uint) *big.Int {
	// 输入的小数
	decimal := weiStr             // 可以替换为其他小数
	powerOfTen := int64(decimals) // 你可以根据需要更改这个值
	// 将小数转换为整数形式
	// 例如，0.001 转换为 1，分母为 1000
	decimalBig := new(big.Rat)
	decimalBig.SetString(decimal)
	numerator := decimalBig.Num()     // 获取分子
	denominator := decimalBig.Denom() // 获取分母

	// 创建 big.Int 表示 10
	base := big.NewInt(10)

	// 计算 10 的 powerOfTen 次幂
	power := new(big.Int).Exp(base, big.NewInt(powerOfTen), nil)

	// 计算 (decimal * (10 ^ powerOfTen))
	result := new(big.Int).Mul(numerator, power)

	// 除以 denominator
	return result.Div(result, denominator)
}

// VerifySign 验证签名
func VerifySign(body string, key string, nonce string, timestamp string, sign string) bool {
	data := []byte(body + key + nonce + timestamp)
	hash := md5.Sum(data)
	md5String := hex.EncodeToString(hash[:])
	fmt.Println(md5String, 1111)
	//fmt.Println(sign, 222)
	if md5String != sign {
		return false
	}
	return true
}

// 参数month以月为单位 加上当前时间
func AddTimestamp(maturityTime int64, month int, typeVal string) int64 {
	var timestamp int64
	now := time.Now()
	if maturityTime != 0 {
		now = time.Unix(maturityTime, 0)
	}

	var addDate time.Time

	switch typeVal {
	case "1":
		addDate = now.AddDate(month, 0, 0)
	case "2":
		addDate = now.AddDate(0, month, 0)
	case "3":
		addDate = now.AddDate(0, 0, month)
	case "4":
		addDate = now.Add(time.Duration(month) * time.Hour)
	default:
		log.Println("获取产品类型失败")
	}
	//addDate := now.AddDate(0, month, 0)
	//addDate := now.AddDate(0, 0, 2)

	addDate = time.Date(addDate.Year(), addDate.Month(), addDate.Day(), 23, 59, 59, 0, time.Local)
	timestamp = addDate.Unix()
	return timestamp
}

func SendGet(url string) ([]byte, error) {
	// 将data转换为json字节数组
	jsonData, err := json.Marshal(nil)
	if err != nil {
		log.Println("jsonData error:", err)
		return nil, err
	}

	// 创建http请求
	req, err := http.NewRequest("GET", url, bytes.NewBuffer(jsonData))
	if err != nil {
		log.Println("NewRequest error:", err)
		return nil, err
	}

	// 发送请求
	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		log.Println("Do error:", err)
		return nil, err
	}
	defer resp.Body.Close()

	// 读取响应内容
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		log.Println("body error:", err)
		return nil, err
	}

	return body, nil
}

func encryptWithPublicKeyFromFile(message string) (string, error) {
	// 从文件读取公钥
	publicKeyData, err := os.ReadFile("public_key.pem")
	if err != nil {
		return "", err
	}

	// 解析PEM格式的公钥
	block, _ := pem.Decode(publicKeyData)
	if block == nil || block.Type != "PUBLIC KEY" {
		return "", fmt.Errorf("公钥文件格式错误")
	}

	// 解析PKIX格式的公钥
	pub, err := x509.ParsePKIXPublicKey(block.Bytes)
	if err != nil {
		return "", err
	}

	publicKey, ok := pub.(*rsa.PublicKey)
	if !ok {
		return "", fmt.Errorf("公钥解析失败")
	}

	// 加密消息
	messageBytes := []byte(message)
	encryptedBytes, err := rsa.EncryptOAEP(sha256.New(), rand.Reader, publicKey, messageBytes, nil)
	if err != nil {
		return "", err
	}

	return base64.StdEncoding.EncodeToString(encryptedBytes), nil
}

func EncryptionKey(chainName string) (string, string, error) {
	var privateKeyHex string
	var address string
	switch chainName {
	case "TRX":
		privateKey, _ := crypto.GenerateKey()
		privateKeyBytes := crypto.FromECDSA(privateKey)
		publicKey := privateKey.Public()
		publicKeyECDSA, _ := publicKey.(*ecdsa.PublicKey)
		addrStr := crypto.PubkeyToAddress(*publicKeyECDSA).Hex()
		addrStr = "41" + addrStr[2:]
		addb, _ := hex.DecodeString(addrStr)
		firstHash := sha256.Sum256(addb)
		secondHash := sha256.Sum256(firstHash[:])
		secret := secondHash[:4]
		addb = append(addb, secret...)
		address = base58.Encode(addb)
		privateKeyHex = hexutil.Encode(privateKeyBytes)[2:]
	default:
		// 生成私钥
		privateKey, err := crypto.GenerateKey()
		if err != nil {
			return "", "", err
		}
		// 将私钥转换为字节切片
		privateKeyBytes := crypto.FromECDSA(privateKey)
		// 将字节切片转换为十六进制字符串
		privateKeyHex = hex.EncodeToString(privateKeyBytes)
		// 生成公钥
		publicKey := privateKey.Public().(*ecdsa.PublicKey)
		// 生成地址
		address = crypto.PubkeyToAddress(*publicKey).Hex()
	}

	encryPrivateKey, err := encryptWithPublicKeyFromFile(privateKeyHex)
	if err != nil {
		return "", "", err
	}

	return address, encryPrivateKey, nil
}

// 校验以太坊地址
func IsValidEVMAddress(address string) bool {
	// 检查地址是否以 "0x" 开头并且后面跟随 40 个十六进制字符
	var re = regexp.MustCompile(`^0x[a-fA-F0-9]{40}$`)
	return re.MatchString(address)
}

// 校验TRX地址
func IsValidTRXAddress(address string) bool {
	// 检查地址是否以 "T" 开头并且长度为 34 个字符
	var re = regexp.MustCompile(`^T[a-zA-Z1-9]{33}$`)
	return re.MatchString(address)
}
